﻿using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;

using LeanEngine.Entity;
using LeanEngine.Data.Linq;

namespace LeanEngine.Data.SqlClient
{
    internal sealed class SqlFunction : IFunction
    {
        #region Singleton Members

        private static SqlFunction _instance = new SqlFunction();
        public static SqlFunction Instance { get { return _instance; } }

        #endregion

        #region IFunction Members

        public string FormatValue(object value)
        {
            if (value == null) return "NULL";
            
            var type = value.GetType();
            
            if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>)))
            {
                type = type.GetGenericArguments()[0];
            }

            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Object:
                    if (!(value is Guid)) throw new NotSupportedException(string.Format("The constant for '{0}' is not supported", value));

                    return FormatValue(value.ToString(), string.Empty);

                case TypeCode.Boolean:
                    return (bool)value ? "1" : "0";

                case TypeCode.DateTime:
                    return FormatValue(EscapeSingleQuotes(Convert.ToString(value, System.Threading.Thread.CurrentThread.CurrentCulture)), string.Empty);

                case TypeCode.Char:                
                case TypeCode.String:
                    return FormatValue(EscapeSingleQuotes(Convert.ToString(value, System.Threading.Thread.CurrentThread.CurrentCulture)), string.Empty);

                default:
                    return Convert.ToString(value, System.Threading.Thread.CurrentThread.CurrentCulture);
            }
        }

        public string FormatValue(object value, string format)
        {
            return string.Format(string.IsNullOrEmpty(format) ? "'{0}'" : format, value);
        }

        public string WrapInBrackets(string value, string tableAlias)
        {
            return !string.IsNullOrEmpty(tableAlias) ? string.Format(tableAlias + ".{0}", value.Trim()) : value.Trim();
        }

        #endregion

        #region Method Members

        internal static string EscapeSingleQuotes(string str)
        {
            if (str.IndexOf('\'') < 0) return str;

            var builder = new StringBuilder();
            foreach (char ch in str)
            {
                builder.Append(ch == '\'' ? "''" : ch.ToString());
            }

            return builder.ToString();
        }

        #endregion
    }
}
